package org.meteorshower.config;


import org.meteorshower.service.IAdminService;
import org.meteorshower.service.IRenterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.test.web.servlet.MockMvc;

import java.util.Arrays;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final String ADMIN_LOGIN_URL = "/api/admin/login";
    private final String RENTER_LOGIN_URL = "/api/renter/login";
    @Autowired
    IAdminService adminService;
    @Autowired
    IRenterService renterService;

    /**
     * 通过对不同身份配置不同的Provider可以将UserDetailService接口解绑，同时，对应的实体类也能够解绑，但是鉴权逻辑需要手写
     * 同时面对实际开发中可能仍然需要一个统一的接口方便调用，所以，这里依然保留UserDetailService和UserDetails接口绑定到对应的业务类和实体类中
     * */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        /**
         * 若配置使用链式请求，则顺序过滤器配置时需以Security内部以注册的Filter为操作类，若使用上文配置的自定义Filter则会出现空指针错误
         * */
        return http.addFilterAt(renterAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterAfter(adminAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests(auth->{
                    //自定义需要额外放行登录路径
                    auth.mvcMatchers("/api/renter/login", "/api/admin/login").permitAll()
                            //给租客开放自己的路径
                            .mvcMatchers("/api/renter/**").hasRole("RENTER")
                            //给管理员开放自己的、房间管理路径
                            .mvcMatchers("/api/admin/**","api/room/**").hasRole("ADMIN")
                            //拒绝所有其他路径
                            .anyRequest().denyAll();
                }).csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session->session.sessionCreationPolicy(SessionCreationPolicy.ALWAYS))
                .build();
    }

    @Bean
    public RenterAuthenticationFilter renterAuthenticationFilter(){
        RenterAuthenticationFilter renterAuthenticationFilter = new RenterAuthenticationFilter(RENTER_LOGIN_URL);
        renterAuthenticationFilter.setAuthenticationManager(AuthenticationManager());
        return renterAuthenticationFilter;
    }

    @Bean
    public AuthenticationManager AuthenticationManager(){
        return new ProviderManager(
                new RenterAuthenticationProvider(renterService),
                new AdminAuthenticationProvider(adminService)
        );
    }

    @Bean
    public AdminAuthenticationFilter adminAuthenticationFilter(){
        AdminAuthenticationFilter adminAuthenticationFilter = new AdminAuthenticationFilter(ADMIN_LOGIN_URL);
        adminAuthenticationFilter.setAuthenticationManager(AuthenticationManager());
        return adminAuthenticationFilter;
    }

}
